package OrderService

import (
	"context"
	"errors"
	"fmt"
	"gdshop-font-api-go/app/entity"
	"gdshop-font-api-go/app/request/OrderReq"
	"gdshop-font-api-go/app/response/AddressResp"
	"gdshop-font-api-go/app/response/CartResp"
	"gdshop-font-api-go/app/response/GoodsResp"
	"gdshop-font-api-go/app/response/OrderResp"
	"gdshop-font-api-go/app/service/AddressService"
	"gdshop-font-api-go/app/service/GoodsActivityService"
	"gdshop-font-api-go/app/service/GoodsLimitService"
	"gdshop-font-api-go/app/service/GoodsService"
	"gdshop-font-api-go/library/response"
	"gdshop-font-api-go/library/tools"
	toolsDb "gdshop-font-api-go/library/tools/db"
	"github.com/gogf/gf/frame/g"
	"github.com/gogf/gf/util/gconv"
	"github.com/gogf/gf/util/gvalid"
	"github.com/syyongx/php2go"
	"math"
	"strconv"
)

func Create(ctx context.Context, parames *OrderReq.Create) *response.JsonResponse {
	if parames.OneData == nil && len(parames.CartData) < 1 {
		return response.FailByRequestMessage(nil, "不支持当前模式")
	}
	var data *OrderResp.Create
	var err error
	// 2021.09.14 商品详情 单项
	if parames.OneData != nil {
		data, err = doCreateOneData(ctx, parames)
		if err != nil {
			return response.FailByRequestMessage(nil, err.Error())
		}
	}
	// 2021.09.14 购物车分组方式
	if len(parames.CartData) > 0 {
		data, err = doCreateCartData(ctx, parames)
		if err != nil {
			return response.FailByRequestMessage(nil, err.Error())
		}
	}

	var addressModel *AddressResp.Item
	if parames.AddressId < 1 {
		// 获取默认收货地址
		addressModel = AddressService.GetMemberDefaultAddress(ctx, parames.MemberId)
	} else {
		addressModel = AddressService.GetMemberAddressById(ctx, parames.MemberId, parames.AddressId)
	}

	// 2022.03.25 判断收货地址限制
	err = GoodsLimitService.CheckAddressLimit(ctx, data.OrderList, addressModel)
	goodsLimitTip := ""
	if err != nil {
		goodsLimitTip = err.Error()
	}

	return response.SuccessByRequestMessageData(nil, "成功",
		g.Map{
			"order_groups":    data.OrderList,
			"discounts":       data.Discounts,
			"address_info":    addressModel,
			"goods_limit_tip": goodsLimitTip,
			"photo_base_url":  g.Cfg().GetString("site.PhotoUrlProfix"),
		})
}

// 检测一条商品
func doCreateOne(ctx context.Context, goods *OrderReq.GoodsItem, memberId uint) (*OrderResp.Goodss, error) {
	// 判断基本参数
	rules := map[string]string{
		"GoodsId":       "required|integer|min:1",
		"GoodsOptionId": "required|integer|min:1",
		"GoodsNum":      "required|integer|min:1",
	}
	msgs := map[string]interface{}{
		"GoodsId": map[string]string{
			"required": "请选择商品",
			"integer":  "商品ID格式错误",
			"min":      "商品ID格式错误",
		},
		"GoodsOptionId": map[string]string{
			"required": "请选择商品规格",
			"integer":  "商品规格ID格式错误",
			"min":      "商品规格ID格式错误",
		},
		"GoodsNum": map[string]string{
			"required": "请填写商品数量",
			"integer":  "商品数量格式错误",
			"min":      "数量不能小于1",
		},
	}

	if e := gvalid.CheckStruct(ctx, goods, rules, msgs); e != nil {
		g.Dump(goods)
		return nil, e
	}

	// 先找出是否有当前商品
	goodsModel, err := GoodsService.GetGoodsModel(ctx, goods.GoodsId)
	if err != nil {
		return nil, err
	}

	// 判断是否是上架状态
	if goodsModel.Status != 1 {
		return nil, errors.New("商品《" + goodsModel.GoodsName + "》已下架")
	}

	// 找出是否有当前商品规格
	optionModel := (*GoodsResp.GoodsOption)(nil)
	for _, option := range goodsModel.Options {
		if option.Id == goods.GoodsOptionId {
			optionModel = option
		}
	}
	if optionModel == nil {
		return nil, errors.New("找不到规格")
	}
	// 数量是否超库存
	if goods.GoodsNum > optionModel.Stock {
		return nil, errors.New(optionModel.Title + "规格库存不足")
	}

	// 只保留一个规格
	goodsModel.Options = []*GoodsResp.GoodsOption{}
	goodsModel.Options = append(goodsModel.Options, optionModel)

	var goodssItem *OrderResp.Goodss
	if err := gconv.Struct(goodsModel, &goodssItem); err != nil {
		return nil, err
	}

	goodssItem.BuyNum = goods.GoodsNum

	goodssItem.DiscountMoney = 0
	goodssItem.Paid = optionModel.SellPrice * int64(goods.GoodsNum)
	goodssItem.SellPrice = optionModel.SellPrice

	return goodssItem, nil
}

/*func doCreateInfo(ctx context.Context, parames *OrderReq.Create) (*OrderResp.Create, error) {
	orderList := []*OrderResp.OrderItem{}
	// 第一期先不考虑分组
	createByGroup, err := doCreateByGroup(ctx, parames.GoodsList, parames.MemberId, parames.CouponIds, 0)
	if err != nil {
		return nil, err
	}
	orderList = append(orderList, createByGroup)
	return &OrderResp.Create{
		OrderList: orderList,
		Discounts: []*OrderResp.DiscountItem{},
	}, nil
}*/

// 按分组创建订单，分组可以是店铺、可以是其他规则
// goodsActivityId = 活动ID，0 为自动选择最优活动，-1 为不使用
func doCreateByGroup(ctx context.Context, goodsLists []*OrderReq.GoodsItem, memberId uint, couponIds []int,
	goodsActivityId int) (*OrderResp.OrderItem, error) {
	createModel := OrderResp.OrderItem{}
	createModel.Goodss = ([]*OrderResp.Goodss)(nil)
	for _, item := range goodsLists {
		goodssItem, err := doCreateOne(ctx, item, memberId)
		if err != nil {
			return nil, err
		}
		// 当前商家信息固定为自营
		createModel.StoreId = goodssItem.StoreId
		createModel.StoreName = getGoodsStoreName(goodssItem.StoreId)
		createModel.Goodss = append(createModel.Goodss, goodssItem)
	}
	if len(createModel.Goodss) > 1 && goodsActivityId == 0 {
		return nil, errors.New("购物车创建订单，请先分组好并确定活动ID之后执行 doCreateByGroup 方法")
	}
	// 活动 扣减 单个商品
	if len(createModel.Goodss) == 1 && goodsActivityId == 0 {
		// 从商品详情创建订单的，可以自动选择最优惠的活动
		err := goodsActivityByCreateByGroup(ctx, &createModel)
		if err != nil {
			return nil, err
		}
		// GroupId 自动处理完，内部设置
	}
	if goodsActivityId > 0 {
		if len(createModel.Goodss) < 1 {
			return nil, errors.New("商品为空")
		}
		// 自行选择了活动，直接读取活动
		err := goodsActivityModelById(ctx, &createModel, goodsActivityId)
		if err != nil {
			return nil, err
		}
		createModel.GroupId = goodsActivityId
	}
	// 可用 优惠券
	/*useCouponOrderSubs, err := getAvailableUseCoupon(ctx, &OrderReq.UseCoupon{
		MemberLogin: BaseReq.MemberLogin{
			MemberId: memberId,
		},
		SubmitItem: OrderReq.SubmitItem{
			StoreId:   createModel.StoreId,
			GoodsList: goodsLists,
		},
	})*/
	useCouponOrderSubs := []OrderReq.OrderSubCoupon{}
	tmpUseCouponOrderSubs, err := getCreateAvailableUseCoupon(ctx, int(memberId), createModel.Goodss)
	if err != nil {
		return nil, err
	}
	// 可用券过滤，按 member_coupon_id 过滤，只保留不重复的
	memberCouponIds := []int{}
	for _, item := range tmpUseCouponOrderSubs {
		if !php2go.InArray(item.MemberCouponId, memberCouponIds) {
			useCouponOrderSubs = append(useCouponOrderSubs, item)
			memberCouponIds = append(memberCouponIds, item.MemberCouponId)
		}
	}
	createModel.CouponNum = len(useCouponOrderSubs)

	createModel.OrderSubCoupons = useCouponOrderSubs
	// 如果选择了券，然而可用券数量小于选择的数量，报错
	/*if len(couponIds) > createModel.CouponNum {
		return nil, errors.New("优惠券不一致，请重新选择")
	}*/
	if createModel.CouponNum > 0 {
		if len(couponIds) > 0 {
			// 如果上送了优惠券，则进行优惠券判断
			if couponIds[0] != 0 {
				createModel.McId = couponIds[0]
				for _, item := range useCouponOrderSubs {
					if createModel.McId == item.MemberCouponId {
						// 目前只匹配第一张
						createModel.SelectCouponId = item.CouponId

						break
					}
				}

				if createModel.SelectCouponId == 0 {
					return nil, errors.New("优惠券无法匹配")
				}
			}
		} else {
			// 未上送
			// 取出最优的优惠券
			var zuiyouhui int64 = 0
			// 当前先设置每个订单只能使用一张券
			for _, item := range useCouponOrderSubs {
				if item.Discount > zuiyouhui {
					zuiyouhui = item.Discount
					createModel.SelectCouponId = item.CouponId
					createModel.McId = item.MemberCouponId
				}
			}
		}

		// 循环计算优惠
		for _, useCouponOrderSub := range useCouponOrderSubs {
			if createModel.McId != useCouponOrderSub.MemberCouponId {
				continue
			}
			for _, goods := range goodsLists {
				if useCouponOrderSub.GoodsOptionId == int(goods.GoodsOptionId) {
					createModel.DiscountMoney += useCouponOrderSub.Discount

				}
			}
			// 根据选中的优惠券，计算商品实付价格
			for _, gs := range createModel.Goodss {
				if gs.Options[0].Id == uint(useCouponOrderSub.GoodsOptionId) {
					gs.Paid = useCouponOrderSub.Paid
					gs.DiscountMoney = useCouponOrderSub.Discount
				}
			}
		}
	}

	// 计算总价
	var totalPrice int = 0
	for _, item := range createModel.Goodss {
		totalPrice += int(item.Options[0].SellPrice) * item.BuyNum
	}
	//createModel.TotalPrice = totalPrice - int(createModel.DiscountMoney)
	createModel.TotalPrice = totalPrice
	createModel.Freight = 0

	return &createModel, nil
}

/*func doCreateCart(ctx context.Context, parames *OrderReq.Create) (*OrderResp.Create, error) {
	// 从购物车取出商品信息
	cartList := []*CartResp.Details{}
	err := toolsDb.GetUnSafaTableAddDeleteWhere(
		ctx,
		"member_cart",
	).Where("member_id=? AND id IN (?)",
		parames.MemberId,
		parames.CartIds,
	).Structs(&cartList)
	if err != nil {
		return nil, err
	}
	if len(cartList) < 1 {
		return nil, errors.New("找不到购物车中的商品")
	}
	// 组装下单数据
	orderData := map[int][]*OrderReq.GoodsItem{}
	for _, item := range cartList {
		if _, ok := orderData[item.ActivityId]; !ok {
			orderData[item.ActivityId] = []*OrderReq.GoodsItem{}
		}
		orderData[item.ActivityId] = append(orderData[item.ActivityId], &OrderReq.GoodsItem{
			GoodsId:       item.GoodsId,
			GoodsNum:      item.Total,
			GoodsOptionId: uint(item.GoodsOptionId),
		})
	}

	//g.Dump(orderData)
	orderList := []*OrderResp.OrderItem{}
	// 购物车下单，如果组大于 1 不使用优惠券
	if len(orderData) > 1 && len(parames.CouponIds) > 0 {
		parames.CouponIds = append(parames.CouponIds, 0)
	}
	// 循环下单
	for activityId, goodsList := range orderData {
		createByGroup, err := doCreateByGroup(ctx, goodsList, parames.MemberId, parames.CouponIds, activityId)
		if err != nil {
			return nil, err
		}
		orderList = append(orderList, createByGroup)
	}

	//orderList = append(orderList, createByGroup)
	return &OrderResp.Create{
		OrderList: orderList,
		Discounts: []*OrderResp.DiscountItem{},
	}, nil
}
*/
func getGoodsStoreName(storeId int) string {
	if storeId == 0 {
		return "自营"
	}

	return "第三方商家"
}

// 自动选择最优惠的活动，只允许从商品详情创建
func goodsActivityByCreateByGroup(ctx context.Context, createModel *OrderResp.OrderItem) error {
	//g.Dump(createModel.Goodss)

	var discountMoney int64 = 0
	for _, item := range createModel.Goodss {
		activitys, err := GoodsActivityService.GetGoodsActivityByGoodsId(ctx, int(item.Id))
		if err != nil {
			return err
		}
		// 判断，防止没有活动
		if len(activitys) < 1 {
			continue
		}
		activity, tmpDm, err := GoodsActivityService.GetMaxDiscountActivity(activitys, item.Paid)
		if err != nil {
			return err
		}

		// 如果 activity = nil 说明没有匹配到
		if activity == nil {
			continue
		}

		//tmpDm := item.Paid - int64(float64(item.Paid)*activitys[0].DiscountRatio)
		discountMoney += tmpDm
		item.Paid -= tmpDm
		item.ActivityPaid = item.Paid
		item.ActivityId = activity.Id
		item.ActivityDiscountMoney = tmpDm
	}

	createModel.ActivityDiscountMoney = discountMoney

	return nil
}

// 根据活动ID，计算优惠
func goodsActivityModelById(ctx context.Context, createModel *OrderResp.OrderItem, activityId int) error {
	activityNow, err := GoodsActivityService.GetGoodsActivityById(ctx, activityId)
	if err != nil {
		return err
	}
	if activityNow == nil {
		return errors.New("找不到活动")
	}
	var totalPrice int64 = 0
	// 先计算 当前分组全部总价
	for _, item := range createModel.Goodss {
		totalPrice += item.Paid
	}

	fmt.Println("总价 ", totalPrice)
	// 计算出总的优惠价
	_, discountMoney, err := GoodsActivityService.GetMaxDiscountActivity([]*entity.GoodsActivity{
		activityNow,
	}, totalPrice)
	if err != nil {
		return err
	}

	fmt.Println("总的优惠价 ", discountMoney)

	// 保持一致性优惠
	var discountMoney2 int64 = 0
	// 分摊到商品上面
	for _, item := range createModel.Goodss {
		// 向上取整的方式
		tmpMoney := math.Ceil(float64(item.Paid) / float64(totalPrice) * float64(discountMoney))
		item.ActivityDiscountMoney = gconv.Int64(strconv.FormatFloat(tmpMoney, 'f', 0, 64))
		discountMoney2 += item.ActivityDiscountMoney
		item.Paid = item.Paid - item.ActivityDiscountMoney
		// 不能小于1分钱
		if item.Paid < 1 {
			// 重算，设置最少 1 分钱
			item.ActivityDiscountMoney -= 1
			item.Paid = 1
			discountMoney2 -= 1
		}
	}

	// 矫正优惠
	if discountMoney2 > discountMoney {
		tmpGoods := createModel.Goodss[0]
		tmpGoods.ActivityDiscountMoney += discountMoney - discountMoney2
		tmpGoods.Paid = tmpGoods.Options[0].SellPrice*int64(tmpGoods.BuyNum) - tmpGoods.ActivityDiscountMoney
	}
	// 少了
	if discountMoney > discountMoney2 {
		tmpGoods := createModel.Goodss[0]
		tmpGoods.ActivityDiscountMoney += discountMoney - discountMoney2
		tmpGoods.Paid = tmpGoods.Options[0].SellPrice*int64(tmpGoods.BuyNum) - tmpGoods.ActivityDiscountMoney
	}
	createModel.ActivityDiscountMoney = discountMoney
	createModel.GroupId = activityNow.Id

	for _, item := range createModel.Goodss {
		// 实付 金额 不能为负数
		if item.Paid < 1 {
			return errors.New(item.GoodsName + " 实付金额为负数")
		}
		item.ActivityPaid = item.Paid
		item.ActivityId = activityNow.Id
	}

	return nil
}

// 针对购物车的，计算活动的
func GoodsActivityByCartModel(carts []*CartResp.Details, activityNow *entity.GoodsActivity) (int64, error) {
	var totalPrice int64 = 0
	// 先计算 当前分组全部总价
	for _, item := range carts {
		totalPrice += item.Paid
	}

	fmt.Println("总价 ", totalPrice)
	// 计算出总的优惠价
	_, discountMoney, err := GoodsActivityService.GetMaxDiscountActivity([]*entity.GoodsActivity{
		activityNow,
	}, totalPrice)
	if err != nil {
		return 0, err
	}

	fmt.Println("总的优惠价 ", discountMoney)

	// 保持一致性优惠
	var discountMoney2 int64 = 0
	// 分摊到商品上面
	for _, item := range carts {
		tmpMoney := float64(item.Paid) / float64(totalPrice) * float64(discountMoney)
		discountMoney2 += gconv.Int64(strconv.FormatFloat(tmpMoney, 'f', 0, 64))
		item.Paid = item.Paid - gconv.Int64(strconv.FormatFloat(tmpMoney, 'f', 0, 64))
	}

	// 矫正优惠
	if discountMoney2 > discountMoney {
		// 多了
		carts[0].Paid -= discountMoney2 - discountMoney
	}
	// 少了
	if discountMoney > discountMoney2 {
		carts[0].Paid -= discountMoney - discountMoney2
	}

	return discountMoney, nil
}

// 单条信息下单，通常是从商品详情过来的
func doCreateOneData(ctx context.Context, parames *OrderReq.Create) (*OrderResp.Create, error) {
	orderList := []*OrderResp.OrderItem{}
	var goodsList []*OrderReq.GoodsItem
	goodsList = append(goodsList, &OrderReq.GoodsItem{
		GoodsId:       parames.OneData.GoodsId,
		GoodsNum:      parames.OneData.GoodsNum,
		GoodsOptionId: uint(parames.OneData.GoodsOptionId),
	})
	createByGroup, err := doCreateByGroup(ctx, goodsList, parames.MemberId, parames.OneData.CouponIds, 0)
	if err != nil {
		return nil, err
	}
	orderList = append(orderList, createByGroup)
	return &OrderResp.Create{
		OrderList: orderList,
		Discounts: []*OrderResp.DiscountItem{},
	}, nil
}

// 从购物车过来的，分组下单
func doCreateCartData(ctx context.Context, parames *OrderReq.Create) (*OrderResp.Create, error) {
	cartIds := []int{}
	for _, item := range parames.CartData {
		cartIds = append(cartIds, item.CartIds...)
	}
	// 防止重复
	if tools.DuplicateInArray(cartIds) > 0 {
		return nil, errors.New("cart_id 包含重复ID")
	}
	// 批量取出购物车信息
	cartList := []*CartResp.Details{}
	err := toolsDb.GetUnSafaTableAddDeleteWhere(
		ctx, "member_cart",
	).Where("member_id=? AND id IN (?)", parames.MemberId, cartIds).Structs(&cartList)
	if err != nil {
		return nil, err
	}
	if len(cartList) < 1 {
		return nil, errors.New("找不到购物车中的商品")
	}

	orderList := []*OrderResp.OrderItem{}

	// 组装下单数据
	for _, item := range parames.CartData {
		var tmpOrderData []*OrderReq.GoodsItem
		for _, cc := range cartList {
			if php2go.InArray(cc.Id, item.CartIds) {
				tmpOrderData = append(tmpOrderData, &OrderReq.GoodsItem{
					GoodsId:       cc.GoodsId,
					GoodsNum:      cc.Total,
					GoodsOptionId: uint(cc.GoodsOptionId),
				})
			}
		}
		createByGroup, err := doCreateByGroup(ctx, tmpOrderData, parames.MemberId, item.CouponIds, item.ActivityId)
		if err != nil {
			return nil, err
		}
		orderList = append(orderList, createByGroup)
	}

	return &OrderResp.Create{
		OrderList: orderList,
		Discounts: []*OrderResp.DiscountItem{},
	}, nil
}
